Unit BFormJSONDiffUnit;

{$mode objfpc}{$H+}

Interface

Uses
  Classes, SysUtils, FileUtil, SynMemo, SynHighlighterDiff, Forms, Controls,
  Graphics, Dialogs, StdCtrls, ExtCtrls, process;

Type

  { TFormJSONDiff }

  TFormJSONDiff = Class(TForm)
    Edit1: TEdit;
    Memo1: TMemo;
    Procedure Edit1KeyPress(Sender: TObject; Var Key: char);
  Private
    { private declarations }
    Function BeatifyJSON(Const aFile: String): String;
    Function BeatifySQL(Const aFile: String): String;
    Function Beatify(Const aString: String): String;
    Function CheckSQLDirty(Const aString: String): Boolean;
    Function CheckIsFPCUnit(Const aString: String): Boolean;
    Function MakeJSONDiff(Const aString: String): String;
    Function MakeStringify(Const aString: String): String;
  Public
    { public declarations }
  End;

Var
  FormJSONDiff: TFormJSONDiff;

Implementation

{$R *.lfm}

{ TFormJSONDiff }

Procedure TFormJSONDiff.Edit1KeyPress(Sender: TObject; Var Key: char);
Var
  aOutput: String;
Begin
  If Key = #13 Then
    Begin
      If CheckIsFPCUnit(Edit1.Text) Then
        aOutput := MakeJSONDiff(Edit1.Text)
      Else
        aOutput := MakeStringify(Edit1.Text);
      Memo1.Lines.Text := aOutput;
    End;
end;

Function TFormJSONDiff.BeatifyJSON(Const aFile: String): String;
Var
  aStringList: TStringList;
Begin
  If Not(FileExists(aFile)) Then Exit;
  aStringList := TStringList.Create;
  With TProcess.Create(nil) Do
    Begin
      CommandLine := 'jsbeautify ' + aFile;
      Options := Options + [poWaitOnExit, poUsePipes];
      Execute;
      aStringList.LoadFromStream(Output);
      Free;
    End;
  Result := aStringList.Text;
  aStringList.Free;
End;

Function TFormJSONDiff.BeatifySQL(Const aFile: String): String;
Var
  aStringList: TStringList;
Begin
  If Not(FileExists(aFile)) Then Exit;
  aStringList := TStringList.Create;
  With TProcess.Create(nil) Do
    Begin
      CommandLine := 'fsqlf ' + aFile;
      Options := Options + [poWaitOnExit, poUsePipes];
      Execute;
      aStringList.LoadFromStream(Output);
      Free;
    End;
  Result := aStringList.Text;
  aStringList.Free;
End;

Function TFormJSONDiff.Beatify(Const aString: String): String;
Var
  aFileName: String = '';
Begin
  With TStringList.Create Do
    Begin
      Text := aString;
      aFileName := GetTempDir + Format('beatbuffer%d.txt', [Random(1000)]);
      SaveToFile(aFileName);
      Free;
    End;
  If CheckSQLDirty(aString) Then
    Result := BeatifySQL(aFileName)
  Else
    Result := BeatifyJSON(aFileName);
  DeleteFile(aFileName);
End;

Function TFormJSONDiff.CheckSQLDirty(Const aString: String): Boolean;
Begin
  Result := TRUE;
  If Pos('SELECT', aString) > 0 Then Exit;
  If Pos('UPDATE', aString) > 0 Then Exit;
  If Pos('DELETE', aString) > 0 Then Exit;
  If Pos('EXECUTE', aString) > 0 Then Exit;
  Result := FALSE;
End;

Function TFormJSONDiff.CheckIsFPCUnit(Const aString: String): Boolean;
Begin
  Result := FALSE;
  If Not(aString[1] = '<') Then Exit;
  If Pos('> but was:', aString) = 0 Then Exit;
  If Not(aString[Length(aString)] = '>') Then Exit;
  Result := TRUE;
End;

Function TFormJSONDiff.MakeJSONDiff(Const aString: String): String;
Var
  i, aIndex: Integer;
  aLeft, aLeftFile, aRight, aRightFile, aDiffFile: String;
Begin
  If Not(CheckIsFPCUnit(aString)) Then Exit;
  aIndex := Pos('but was:', aString);
  aLeft := Copy(aString, 2, aIndex - 4);
  aLeft := Beatify(aLeft);
  aLeftFile := GetTempDir + Format('leftbuffer%d.txt', [Random(1000)]);
  With TStringList.Create Do
    Begin
      Text := aLeft;
      SaveToFile(aLeftFile);
      Free;
    End;

  aRight := Copy(aString, aIndex + 10, Length(aString) - 10 - aIndex);
  aRight := Beatify(aRight);
  aRightFile := GetTempDir + Format('rightbuffer%d.txt', [Random(1000)]);
  With TStringList.Create Do
    Begin
      Text := aRight;
      SaveToFile(aRightFile);
      Free;
    End;

  aDiffFile := GetTempDir + Format('diffbuffer%d.txt', [Random(1000)]);
  With TProcess.Create(nil) Do
    Begin
      CommandLine := Format('bash -c "diff %s %s > %s"',
        [aLeftFile, aRightFile, aDiffFile]);
      Options := Options + [poWaitOnExit];
      Execute;
      Free;
    End;

  With TStringList.Create Do
    Begin
      LoadFromFile(aDiffFile);
      Result := Text;
      Free;
    End;
  //DeleteFile(aLeftFile);
  //DeleteFile(aRightFile);
  //DeleteFile(aDiffFile);
End;

Function TFormJSONDiff.MakeStringify(Const aString: String): String;
Var
  i, j: Integer;
  aBuffer: String;
Begin
  Result := Beatify(aString);
  With TStringList.Create Do
    Begin
      Text := Result;
      For i := 0 To Count - 1 Do
        Begin
          aBuffer := Strings[i];
          For j := 1 To Length(aBuffer) Do
            If Not(aBuffer[j] = #32) Then
              Begin
                system.Insert(#39, aBuffer, j);
                If i = Count - 1 Then
                  aBuffer += #39';'
                Else
                  aBuffer += #39' +';
                aBuffer := StringReplace(aBuffer, '": ', '":', [rfReplaceAll]);
                Strings[i] := aBuffer;
                Break;
              End;
        End;
      Result := Text;
      Free;
    End;
End;

End.

